import json
import os
from typing import List, Dict, Any, Optional
from dataclasses import dataclass, asdict
from datetime import datetime
import uuid

@dataclass
class Question:
    id: str = None  # 添加默认值
    question: str = ""
    answer: str = ""
    steps: List[Dict[str, Any]] = None
    tags: Dict[str, Any] = None
    is_favorite: bool = False
    last_review_date: Optional[str] = None
    review_count: int = 0
    correct_count: int = 0
    mastery_level: float = 0.0
    wrong_count: int = 0
    wrong_steps: List[int] = None
    
    def __post_init__(self):
        # 确保 id 存在
        if self.id is None:
            self.id = str(uuid.uuid4())
        # 确保 steps 是列表
        if self.steps is None:
            self.steps = []
        # 确保 tags 是字典
        if self.tags is None:
            self.tags = {"knowledge_tags": []}

class QuestionBank:
    def __init__(self):
        self.questions = []
        # 确保"问的问题"目录存在
        self._ensure_question_category()
        self.load_questions()
    
    def _ensure_question_category(self):
        """确保'问的问题'目录存在"""
        try:
            question_dir = os.path.join('./dataset', '问的问题')
            if not os.path.exists(question_dir):
                print(f"创建目录: {question_dir}")
                os.makedirs(question_dir)
            
            # 创建空的题目文件
            questions_file = os.path.join(question_dir, 'questions.json')
            if not os.path.exists(questions_file):
                print(f"创建文件: {questions_file}")
                with open(questions_file, 'w', encoding='utf-8') as f:
                    json.dump([], f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"创建'问的问题'目录失败: {e}")
    
    def load_questions(self):
        """从dataset目录加载所有题目数据"""
        try:
            # 获取dataset目录下的所有子目录
            dataset_dir = './dataset'
            if not os.path.exists(dataset_dir):
                print(f"数据集目录 {dataset_dir} 不存在")
                return
            
            # 遍历所有子目录
            for subject_dir in os.listdir(dataset_dir):
                subject_path = os.path.join(dataset_dir, subject_dir)
                if not os.path.isdir(subject_path):
                    continue
                
                print(f"正在加载 {subject_dir} 科目的题目...")
                
                # 查找目录下的所有JSON文件
                for file_name in os.listdir(subject_path):
                    if not file_name.endswith('.json'):
                        continue
                    
                    file_path = os.path.join(subject_path, file_name)
                    try:
                        with open(file_path, 'r', encoding='utf-8') as f:
                            data = json.load(f)
                            
                            # 处理不同格式的JSON文件
                            questions = []
                            if isinstance(data, dict):
                                if 'steps' in data:
                                    questions = data['steps']
                                elif 'datas' in data:
                                    questions = data['datas']
                                elif 'questions' in data:
                                    questions = data['questions']
                                elif 'data' in data:
                                    questions = data['data']
                            elif isinstance(data, list):
                                questions = data
                            
                            # 为每个题目添加来源信息
                            for q in questions:
                                if isinstance(q, dict):
                                    # 确保题目有基本字段
                                    if 'question' not in q:
                                        continue
                                    
                                    # 添加来源信息
                                    q['source'] = {
                                        'subject': subject_dir,
                                        'file': file_name
                                    }
                                    
                                    # 确保tags字段存在且格式正确
                                    if 'tags' not in q:
                                        q['tags'] = {}
                                    if not isinstance(q['tags'], dict):
                                        q['tags'] = {}
                                    
                                    # 确保knowledge_tags存在
                                    if 'knowledge_tags' not in q['tags']:
                                        q['tags']['knowledge_tags'] = []
                                    
                                    # 确保steps字段存在且格式正确
                                    if 'steps' not in q:
                                        q['steps'] = []
                                    if not isinstance(q['steps'], list):
                                        q['steps'] = []
                                    
                                    # 确保每个step都有content字段
                                    for step in q['steps']:
                                        if not isinstance(step, dict):
                                            step = {'content': str(step)}
                                        if 'content' not in step:
                                            step['content'] = str(step)
                                    
                                    # 添加其他必要字段
                                    if 'id' not in q:
                                        q['id'] = str(uuid.uuid4())
                                    if 'is_favorite' not in q:
                                        q['is_favorite'] = False
                                    if 'last_review_date' not in q:
                                        q['last_review_date'] = None
                                    if 'review_count' not in q:
                                        q['review_count'] = 0
                                    if 'correct_count' not in q:
                                        q['correct_count'] = 0
                                    if 'mastery_level' not in q:
                                        q['mastery_level'] = 0.0
                                    
                                    self.questions.append(q)
                            
                            print(f"从 {file_name} 加载了 {len(questions)} 道题目")
                            
                    except Exception as e:
                        print(f"加载文件 {file_path} 失败: {e}")
                        continue
            
            print(f"成功加载 {len(self.questions)} 道题目")
            
        except Exception as e:
            print(f"加载题目失败: {e}")
            self.questions = []
    
    def get_all_questions(self) -> List[Question]:
        """获取所有题目"""
        questions = []
        for q in self.questions:
            try:
                if isinstance(q, dict):
                    questions.append(Question(
                        id=q.get('id', str(uuid.uuid4())),
                        question=q.get('question', ''),
                        answer=q.get('answer', ''),
                        steps=q.get('steps', []),
                        tags=q.get('tags', {'knowledge_tags': []}),
                        is_favorite=q.get('is_favorite', False),
                        last_review_date=q.get('last_review_date'),
                        review_count=q.get('review_count', 0),
                        correct_count=q.get('correct_count', 0),
                        mastery_level=q.get('mastery_level', 0.0)
                    ))
            except Exception as e:
                print(f"转换题目数据失败: {e}")
                continue
        return questions
    
    def get_knowledge_tags(self):
        """获取所有知识点标签"""
        tags = set()
        for question in self.questions:
            if isinstance(question, dict) and 'tags' in question:
                if isinstance(question['tags'], dict):
                    # 如果tags是字典，获取其中的knowledge_tags
                    if 'knowledge_tags' in question['tags']:
                        tags.update(question['tags']['knowledge_tags'])
                elif isinstance(question['tags'], list):
                    # 如果tags是列表，直接添加所有标签
                    tags.update(question['tags'])
        return sorted(list(tags))
    
    def get_knowledge_tags_by_subject(self, subject: str) -> List[str]:
        """获取指定学科的所有知识点标签"""
        tags = set()
        for question in self.questions:
            if isinstance(question, dict):
                # 只筛选该学科
                if subject != "全部" and question.get('source', {}).get('subject') != subject:
                    continue
                if 'tags' in question and isinstance(question['tags'], dict):
                    for tag in question['tags'].get('knowledge_tags', []):
                        # 如果标签包含学科前缀，去掉前缀
                        if '/' in tag:
                            tag = tag.split('/')[-1]
                        tags.add(tag)
        
        # 打印调试信息
        print(f"Getting knowledge tags for subject: {subject}")
        print(f"Found tags: {sorted(list(tags))}")
        
        return sorted(list(tags))
    
    def filter_questions(self, filters):
        """根据筛选条件过滤题目"""
        filtered_questions = self.questions.copy()
        
        # 学科筛选
        if filters.get('subject') and filters['subject'] != "全部":
            filtered_questions = [q for q in filtered_questions 
                                if q.get('source', {}).get('subject') == filters['subject']]
        
        # 知识点标签筛选
        if filters.get('knowledge_tags') and filters['knowledge_tags']:
            # 获取所有标签（包括子标签）
            all_tags = set()
            for tag in filters['knowledge_tags']:
                all_tags.add(tag)
                # 添加父标签
                if '/' in tag:
                    parent_tag = tag.split('/')[0]
                    all_tags.add(parent_tag)
                # 添加子标签
                for q in filtered_questions:
                    if isinstance(q.get('tags', {}).get('knowledge_tags'), list):
                        for q_tag in q['tags']['knowledge_tags']:
                            if q_tag.startswith(f"{tag}/"):
                                all_tags.add(q_tag)
            
            # 使用更灵活的匹配逻辑
            filtered_questions = [q for q in filtered_questions 
                                if any(self._is_tag_match(tag, q.get('tags', {}).get('knowledge_tags', []))
                                      for tag in all_tags)]
        
        # 难度筛选
        if filters.get('difficulty') and filters['difficulty'] != "全部":
            difficulty_map = {"简单": 1, "中等": 2, "困难": 3}
            difficulty = difficulty_map.get(filters['difficulty'])
            if difficulty:
                filtered_questions = [q for q in filtered_questions 
                                    if q.get('tags', {}).get('difficulty') == difficulty]
        
        # 复习状态筛选
        if filters.get('review_status') and filters['review_status'] != "全部":
            now = datetime.now()
            if filters['review_status'] == "未复习":
                filtered_questions = [q for q in filtered_questions 
                                    if not q.get('last_review_date')]
            elif filters['review_status'] == "已复习":
                filtered_questions = [q for q in filtered_questions 
                                    if q.get('last_review_date')]
            elif filters['review_status'] == "最近复习":
                filtered_questions = [q for q in filtered_questions 
                                    if q.get('last_review_date') and 
                                    (now - datetime.strptime(q['last_review_date'], '%Y-%m-%d')).days <= 7]
        
        # 收藏状态筛选
        if filters.get('favorite_status') and filters['favorite_status'] != "全部":
            if filters['favorite_status'] == "已收藏":
                filtered_questions = [q for q in filtered_questions if q.get('is_favorite')]
            elif filters['favorite_status'] == "未收藏":
                filtered_questions = [q for q in filtered_questions if not q.get('is_favorite')]
        
        # 步骤关键词筛选
        if filters.get('step_keyword'):
            keyword = filters['step_keyword'].lower()
            filtered_questions = [q for q in filtered_questions 
                                if any(keyword in str(step).lower() 
                                      for step in q.get('steps', []))]
        
        return filtered_questions
    
    def _is_tag_match(self, search_tag: str, question_tags: list) -> bool:
        """检查标签是否匹配
        
        Args:
            search_tag (str): 搜索的标签
            question_tags (list): 题目的标签列表
            
        Returns:
            bool: 是否匹配
        """
        if not question_tags:
            return False
            
        # 将搜索标签转换为小写
        search_tag = search_tag.lower()
        
        # 检查每个题目标签
        for tag in question_tags:
            tag = tag.lower()
            
            # 完全匹配
            if tag == search_tag:
                return True
                
            # 父标签匹配（例如：搜索"数学"匹配"数学/代数"）
            if '/' in tag and tag.split('/')[0] == search_tag:
                return True
                
            # 子标签匹配（例如：搜索"数学/代数"匹配"数学"）
            if '/' in search_tag and tag == search_tag.split('/')[0]:
                return True
        
        return False
    
    def update_question(self, question_id, updates):
        """更新题目信息"""
        for question in self.questions:
            if question['id'] == question_id:
                question.update(updates)
                break
    
    def save_questions(self):
        """保存题目数据到原始文件"""
        try:
            print("开始保存题目...")
            print(f"当前内存中的题目数量: {len(self.questions)}")
            
            # 按来源分组题目
            questions_by_source = {}
            for q in self.questions:
                if not isinstance(q, dict):
                    print(f"跳过非字典题目: {q}")
                    continue
                if 'source' not in q:
                    print(f"跳过无来源题目: {q}")
                    continue
                
                source = q['source']
                key = (source['subject'], source['file'])
                if key not in questions_by_source:
                    questions_by_source[key] = []
                questions_by_source[key].append(q)
            
            print(f"按来源分组的题目: {questions_by_source}")
            
            # 保存到对应的文件
            for (subject, file_name), questions in questions_by_source.items():
                file_path = os.path.join('./dataset', subject, file_name)
                try:
                    # 确保目录存在
                    os.makedirs(os.path.dirname(file_path), exist_ok=True)
                    print(f"保存题目到文件: {file_path}")
                    print(f"题目数量: {len(questions)}")
                    print(f"题目内容: {questions}")
                    
                    with open(file_path, 'w', encoding='utf-8') as f:
                        json.dump(questions, f, ensure_ascii=False, indent=2)
                    print(f"成功保存 {len(questions)} 道题目到 {file_path}")
                except Exception as e:
                    print(f"保存文件 {file_path} 失败: {e}")
                    continue
            
        except Exception as e:
            print(f"保存题目失败: {e}")
            raise
    
    def add_question(self, question: Question):
        """添加题目"""
        try:
            # 确保题目有 id
            if not question.id:
                question.id = str(uuid.uuid4())
            
            question_dict = asdict(question)
            print(f"准备添加题目: {question_dict}")
            
            # 如果是"问的问题"分类，确保添加到正确的文件中
            if '问的问题' in question.tags.get('knowledge_tags', []):
                question_dict['source'] = {
                    'subject': '问的问题',
                    'file': 'questions.json'
                }
            else:
                # 如果没有指定来源，使用默认来源
                if 'source' not in question_dict:
                    question_dict['source'] = {
                        'subject': '问的问题',
                        'file': 'questions.json'
                    }
            
            print(f"添加题目到内存: {question_dict}")
            self.questions.append(question_dict)
            
            # 立即保存到文件
            self.save_questions()
            
            # 打印调试信息
            print(f"添加题目成功: {question_dict}")
            print(f"当前题目数量: {len(self.questions)}")
            
        except Exception as e:
            print(f"添加题目失败: {e}")
            raise
    
    def edit_question(self, index: int, question: Question):
        """编辑题目"""
        if 0 <= index < len(self.questions):
            self.questions[index] = asdict(question)
            self.save_questions()
    
    def delete_question(self, index: int) -> bool:
        """删除指定索引的题目
        
        Args:
            index (int): 要删除的题目索引
            
        Returns:
            bool: 是否删除成功
        """
        try:
            if 0 <= index < len(self.questions):
                # 获取要删除的题目
                question = self.questions[index]
                
                # 从内存中删除
                del self.questions[index]
                
                # 保存到文件
                self.save_questions()
                
                # 如果题目有源文件，检查是否需要删除空文件
                if 'source' in question:
                    source = question['source']
                    file_path = os.path.join('./dataset', source['subject'], source['file'])
                    if os.path.exists(file_path):
                        # 检查文件是否为空
                        with open(file_path, 'r', encoding='utf-8') as f:
                            data = json.load(f)
                            if not data:  # 如果文件为空
                                os.remove(file_path)
                                print(f"删除空文件: {file_path}")
                
                print(f"成功删除题目: {question.get('id', 'unknown')}")
                return True
            return False
        except Exception as e:
            print(f"删除题目失败: {e}")
            return False
    
    def get_questions_by_difficulty(self, difficulty: str) -> List[Question]:
        """按难度筛选题目
        
        Args:
            difficulty (str): 难度级别（"全部"、"简单"、"中等"、"困难"）
        """
        if difficulty == "全部":
            return self.get_all_questions()
        
        difficulty_map = {"简单": 1, "中等": 2, "困难": 3}
        diff_value = difficulty_map.get(difficulty, 0)
        
        return [Question(**q) for q in self.questions 
                if q.get('tags', {}).get('difficulty') == diff_value]
    
    def get_questions_by_knowledge(self, knowledge_tag: str) -> List[Question]:
        """按知识点筛选题目
        
        Args:
            knowledge_tag (str): 知识点标签
        """
        return [Question(**q) for q in self.questions 
                if knowledge_tag in q.get('tags', {}).get('knowledge_tags', [])]
    
    def get_questions_by_year(self, year: str) -> List[Question]:
        """按年份筛选题目
        
        Args:
            year (str): 年份（"全部"或具体年份）
        """
        if year == "全部":
            return self.get_all_questions()
        
        return [Question(**q) for q in self.questions 
                if str(year) in q.get('tags', {}).get('year', '')]
    
    def get_questions_by_review_status(self, status: str) -> List[Question]:
        """按复习状态筛选题目
        
        Args:
            status (str): 复习状态（"全部"、"未复习"、"已复习"、"最近复习"）
        """
        if status == "全部":
            return self.get_all_questions()
        
        now = datetime.now()
        questions = []
        
        for q in self.questions:
            last_review = q.get('last_review')
            if status == "未复习" and not last_review:
                questions.append(Question(**q))
            elif status == "已复习" and last_review:
                questions.append(Question(**q))
            elif status == "最近复习" and last_review:
                # 最近7天内的复习
                review_date = datetime.fromisoformat(last_review)
                if (now - review_date).days <= 7:
                    questions.append(Question(**q))
        
        return questions
    
    def search_questions(self, keyword: str) -> List[Question]:
        """搜索题目
        
        Args:
            keyword (str): 搜索关键词
        """
        if not keyword:
            return self.get_all_questions()
        
        keyword = keyword.lower()
        results = []
        
        for q in self.questions:
            # 搜索题目内容
            question_text = str(q.get('question', '')).lower()
            if keyword in question_text:
                results.append(Question(**q))
                continue
            
            # 搜索答案
            answer_text = str(q.get('answer', '')).lower()
            if keyword in answer_text:
                results.append(Question(**q))
                continue
            
            # 搜索知识点标签
            knowledge_tags = [str(tag).lower() for tag in q.get('tags', {}).get('knowledge_tags', [])]
            if any(keyword in tag for tag in knowledge_tags):
                results.append(Question(**q))
                continue
            
            # 搜索解题步骤
            steps = q.get('steps', [])
            for step in steps:
                step_text = str(step.get('step', '')).lower()
                if keyword in step_text:
                    results.append(Question(**q))
                    break
        
        return results
    
    def get_questions_by_step(self, step_keyword: str) -> List[Question]:
        """按步骤关键词筛选题目
        
        Args:
            step_keyword (str): 步骤关键词
        """
        if not step_keyword:
            return self.get_all_questions()
        
        step_keyword = step_keyword.lower()
        results = []
        
        for q in self.questions:
            steps = q.get('steps', [])
            for step in steps:
                step_text = str(step.get('step', '')).lower()
                if step_keyword in step_text:
                    results.append(Question(**q))
                    break
        
        return results
    
    def toggle_favorite(self, index: int):
        """切换收藏状态"""
        if 0 <= index < len(self.questions):
            self.questions[index]['is_favorite'] = not self.questions[index].get('is_favorite', False)
            self.save_questions()
    
    def update_review(self, index: int, is_correct: bool, wrong_steps: List[int] = None):
        """更新复习记录
        
        Args:
            index (int): 题目索引
            is_correct (bool): 是否答对
            wrong_steps (List[int], optional): 错误的步骤索引列表. Defaults to None.
        """
        if 0 <= index < len(self.questions):
            question = self.questions[index]
            current_time = datetime.now()
            
            # 更新复习时间
            question['last_review_date'] = current_time.strftime('%Y-%m-%d')
            question['review_count'] = question.get('review_count', 0) + 1
            
            # 更新正确/错误次数
            if is_correct:
                question['correct_count'] = question.get('correct_count', 0) + 1
            else:
                question['wrong_count'] = question.get('wrong_count', 0) + 1
            
            # 记录错误的步骤
            if wrong_steps:
                if 'wrong_steps_history' not in question:
                    question['wrong_steps_history'] = []
                question['wrong_steps_history'].append({
                    'date': question['last_review_date'],
                    'steps': wrong_steps
                })
            
            # 计算掌握程度
            total_reviews = question['review_count']
            correct_reviews = question['correct_count']
            
            # 基础掌握度（基于总正确率）
            base_mastery = correct_reviews / total_reviews if total_reviews > 0 else 0
            
            # 最近表现（只看最近5次）
            recent_reviews = min(5, total_reviews)
            recent_correct = min(correct_reviews, recent_reviews)
            recent_mastery = recent_correct / recent_reviews if recent_reviews > 0 else 0
            
            # 连续正确奖励
            consecutive_correct = 0
            if 'review_history' not in question:
                question['review_history'] = []
            
            # 添加当前复习记录
            question['review_history'].append({
                'date': question['last_review_date'],
                'is_correct': is_correct
            })
            
            # 计算连续正确次数
            for review in reversed(question['review_history']):
                if review['is_correct']:
                    consecutive_correct += 1
                else:
                    break
            
            # 连续正确奖励系数（最多奖励0.2）
            consecutive_bonus = min(consecutive_correct * 0.04, 0.2)
            
            # 计算最终掌握度
            # 1. 基础掌握度占40%
            # 2. 最近表现占40%
            # 3. 连续正确奖励占20%
            final_mastery = (base_mastery * 0.4 + recent_mastery * 0.4 + consecutive_bonus)
            
            # 确保掌握度在0-1之间
            question['mastery_level'] = max(0.0, min(1.0, final_mastery))
            
            # 如果掌握度达到0.9以上，标记为已掌握
            if question['mastery_level'] >= 0.9:
                question['is_mastered'] = True
            else:
                question['is_mastered'] = False
            
            # 保存更新
            self.save_questions()
            
            # 打印调试信息
            print(f"题目 {question.get('id', 'unknown')} 更新掌握度:")
            print(f"- 总复习次数: {total_reviews}")
            print(f"- 正确次数: {correct_reviews}")
            print(f"- 基础掌握度: {base_mastery:.2f}")
            print(f"- 最近掌握度: {recent_mastery:.2f}")
            print(f"- 连续正确奖励: {consecutive_bonus:.2f}")
            print(f"- 最终掌握度: {question['mastery_level']:.2f}")
            print(f"- 是否掌握: {question['is_mastered']}")
            
            # 返回更新后的题目，以便更新学习统计
            return question
        
        return None
    
    def export_questions(self, file_path: str, questions: List[Question] = None) -> None:
        """导出题目到文件"""
        if questions is None:
            questions = self.questions
        
        data = {
            "datas": [asdict(q) for q in questions],
            "export_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        }
        
        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    
    def get_favorite_questions(self) -> List[Question]:
        """获取收藏的题目"""
        return [q for q in self.questions if q.get('is_favorite', False)]
    
    def get_recent_reviewed_questions(self, days: int = 7) -> List[Question]:
        """获取最近复习的题目"""
        recent = []
        for q in self.questions:
            if q.get('last_review'):
                review_date = datetime.strptime(q['last_review'], "%Y-%m-%d %H:%M:%S")
                if (datetime.now() - review_date).days <= days:
                    recent.append(Question(**q))
        return recent
    
    def get_difficulty_distribution(self) -> Dict[int, int]:
        """获取难度分布"""
        distribution = {}
        for q in self.questions:
            difficulty = q.get('tags', {}).get('difficulty')
            if difficulty is not None:
                distribution[difficulty] = distribution.get(difficulty, 0) + 1
        return distribution
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取题库统计信息"""
        total = len(self.questions)
        favorites = len([q for q in self.questions if q.get('is_favorite', False)])
        recent = len(self.get_recent_reviewed_questions())
        
        # 计算正确率
        total_reviews = sum(q.get('review_count', 0) for q in self.questions)
        total_correct = sum(q.get('correct_count', 0) for q in self.questions)
        accuracy = total_correct / total_reviews if total_reviews > 0 else 0
        
        return {
            "total_questions": total,
            "favorite_questions": favorites,
            "recent_reviewed": recent,
            "total_reviews": total_reviews,
            "accuracy": accuracy,
            "difficulty_distribution": self.get_difficulty_distribution(),
            "knowledge_tags": self.get_knowledge_tags(),
            "knowledge_tag_count": len(self.get_knowledge_tags())
        }
    
    def get_subjects(self):
        """获取所有科目"""
        subjects = set()
        for q in self.questions:
            if isinstance(q, dict) and 'source' in q:
                subjects.add(q['source']['subject'])
        return sorted(list(subjects))
    
    def get_questions_by_subject(self, subject):
        """获取指定科目的题目"""
        return [q for q in self.questions 
                if isinstance(q, dict) and 
                q.get('source', {}).get('subject') == subject]
    
    def get_knowledge_tags_by_subject(self, subject: str) -> List[str]:
        """获取指定科目的所有知识点标签
        
        Args:
            subject (str): 科目名称
            
        Returns:
            List[str]: 知识点标签列表
        """
        knowledge_tags = set()
        for question in self.questions:
            if isinstance(question, dict):
                tags = question.get('tags', {})
                if isinstance(tags, dict):
                    subject_tags = tags.get('knowledge_tags', [])
                    if isinstance(subject_tags, list):
                        for tag in subject_tags:
                            if tag.startswith(f"{subject}/"):
                                knowledge_tags.add(tag.split('/')[-1])
        return sorted(list(knowledge_tags)) 